/**
 * Contains the data model of the project
 */

if(!mindgraph) {
    var mindgraph = {};
}

mindgraph.theory = {};

mindgraph.theory.previousStateKeys = {};
mindgraph.theory.updateCounter = 0;

mindgraph.theory.stateHandler = function (state) {
        var previousStateKeys = mindgraph.theory.previousStateKeys;
        var updateCounter = ++mindgraph.theory.updateCounter;

	for(var key in state) {
            //console.log(key, state[key]);
		var stateValue = state[key];
		mindgraph.updateIdCount(key);

		var element = mindgraph.theory.Model.createOrFind({id: key, type: mindgraph.theory.types.node});
		element.dataUpdate(stateValue);
                
                previousStateKeys[key] = updateCounter;
	}
        for(key in previousStateKeys) {
            var value = previousStateKeys[key];
            if(value !== updateCounter) {
                delete previousStateKeys[key];
                mindgraph.theory.Model.remove(key);
            }
        }
        mindgraph.theory.updateAll();
}

mindgraph.theory.types = {
	node: "node",
	edge: "edge",
	connectionTypes: {none: "none", empty: "empty", full: "full"}
}

mindgraph.theory.Model = {
	elements: {},
        // tries to find the element, returns undefined if it isn't there
	find: function (id) {
		if(id !== undefined && this.elements[id] !== undefined) {
                    return this.elements[id];
                }
		return undefined;
	},
	// creates a new element
	create: function (setup) {
		var types = mindgraph.theory.types;
		if (setup.type !== types.node && setup.type !== types.edge) {
			throw {
				message: "Can not create element of type: [" + setup.type + "]"
			};
		}
                if(setup.id && this.elements[setup.id]) {
                    throw {
                        type: "ElementCreationException",
                        message: "Element with id '"+setup.id+"' already exists."
                    }
                }
		var creator = function() {};
		creator.prototype = (setup.type === types.node) ? new mindgraph.theory.NodeBase() : new mindgraph.theory.EdgeBase();
		var newElement = new creator();
		if(setup) {
			for(var key in setup) {
				if(key && setup.hasOwnProperty(key) && key !== "type") {
					newElement[key] = setup[key];
				}
			}
		}
		if(setup.id === undefined) newElement.id = mindgraph.generateElementId();
		this.elements[newElement.id] = newElement;
		return newElement;		
	},
	// tries to find an element, creates it if it doesn't exist
	createOrFind: function(setup) {
		var result = undefined;
		if (setup && setup.id) {
			result = this.find(setup.id);
		}
		if(!result) {
			result = this.create(setup);
		}
		return result;
	},
	// return value is true if deletion was successful
	remove: function(id) {
		if(this.elements[id]) {
                        // TODO: also call the relevant method on the object
			delete(this.elements[id]);
			return this.elements[id] === undefined;
		} else {
			return false;
		}
	},
        removeAll: function() {
            for(var id in this.elements) {
                this.remove(id);
            }
        }
}

mindgraph.theory.ConnectionType = {
	none: "none",
	empty: "empty",
	full: "full"
}

mindgraph.theory.SyncStatusType = {
	synced: "synced",
	clientUpdated: "client",
	serverUpdated: "server"
}

mindgraph.theory.ObjectBase = {
	id: "",
	text: "",
	origamiObject: undefined,
        syncStatus: mindgraph.theory.SyncStatusType.synced,
        dataUpdate: function(newState) {
            for(var key in newState) {
                if(this[key]) {
                    if(newState[key] !== this[key]) {
                        this.syncStatus = mindgraph.theory.SyncStatusType.serverUpdated;
                        this[key] = newState[key];
                    }
                } else {
                    this.syncStatus = mindgraph.theory.SyncStatusType.serverUpdated;
                    this[key] = newState[key];
                }
            }
        },
        update: function() {
            this.origamiObject = mindgraph.origami.Model.create();
        }
}

mindgraph.theory.NodeBase = function () {
	this.type = mindgraph.theory.types.node;
	this.connections = [];
}
mindgraph.theory.NodeBase.prototype = mindgraph.theory.ObjectBase;

mindgraph.theory.EdgeBase = function () {
	this.type = mindgraph.theory.types.edge;
	this.node1 = undefined;
	this.node2 = undefined;
	this.arrow1 = mindgraph.theory.ConnectionType.none;
	this.arrow2 = mindgraph.theory.ConnectionType.none;
}
mindgraph.theory.EdgeBase.prototype = mindgraph.theory.ObjectBase;

mindgraph.theory.updateAll = function () {
    for(var id in mindgraph.theory.Model.elements) {
        var value = mindgraph.theory.Model.elements[id];
        if(value) {
            value.update();
        }
    }
}
